#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WMS Simple 客户端GUI
纯客户端程序，连接到现有的API服务器
"""

import os
import sys
import tkinter as tk
from tkinter import ttk, messagebox
import requests
import threading
import time
import json
from pathlib import Path
from typing import Dict, List, Any

# 添加项目根目录到Python路径
current_dir = Path(__file__).parent
sys.path.insert(0, str(current_dir))

# 设置工作目录
os.chdir(current_dir)

# 导入路径管理器
from src.core.path_manager import path_manager

class ClientConfig:
    """客户端配置"""
    def __init__(self):
        # 使用路径管理器获取配置文件路径
        self.config_file = path_manager.get_config_file("client_config.json")
        self.default_config = {
            "api_host": "127.0.0.1",
            "api_port": 58501,
            "connection_timeout": 5,
            "auto_refresh_interval": 30
        }
        self.load_config()
    
    def load_config(self):
        """加载配置"""
        try:
            if self.config_file.exists():
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config_data = json.load(f)
                    self.config = {**self.default_config, **config_data}
            else:
                self.config = self.default_config.copy()
                self.save_config()
        except Exception as e:
            print(f"加载配置失败: {e}")
            self.config = self.default_config.copy()
    
    def save_config(self):
        """保存配置"""
        try:
            # 确保配置目录存在
            self.config_file.parent.mkdir(parents=True, exist_ok=True)
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(self.config, f, indent=2, ensure_ascii=False)
        except Exception as e:
            print(f"保存配置失败: {e}")
    
    @property
    def api_base_url(self):
        return f"http://{self.config['api_host']}:{self.config['api_port']}"

class WMSClientUI:
    """WMS客户端UI"""
    
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("WMS 样品管理客户端")
        self.root.geometry("1200x800")
        self.root.configure(bg='#F8F9FA')  # 统一背景色
        
        # 配置管理
        self.config = ClientConfig()
        
        # 状态变量
        self.server_connected = False
        self.auto_refresh_enabled = True
        
        # UI组件
        self.status_label = None
        self.server_label = None
        self.notebook = None
        self.plate_tree = None
        self.query_tree = None
        
        # 样品管理相关
        self.sample_id_var = tk.StringVar()
        self.plate_combo_var = tk.StringVar() 
        self.position_var = tk.StringVar()
        self.remove_sample_var = tk.StringVar()
        self.plate_combo = None
        
        # 查询相关
        self.search_sample_var = tk.StringVar()
        
        # 料位显示相关
        self.position_canvas = None
        self.position_frame = None
        self.current_plate_positions = []
        self.highlighted_position = None
        
        # 创建界面
        self.create_widgets()
        
        # 启动连接检查
        self.start_connection_check()
        
        # 尝试连接服务器
        self.check_connection()
    
    def create_widgets(self):
        """创建所有UI组件"""
        # 主框架
        main_frame = tk.Frame(self.root, bg='#F8F9FA', padx=15, pady=15)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 连接面板
        self.create_connection_panel(main_frame)
        
        # 选项卡
        self.create_notebook(main_frame)
    
    def create_connection_panel(self, parent):
        """创建连接状态面板"""
        conn_frame = tk.LabelFrame(parent, text="🔗 服务器连接", 
                                  font=('Microsoft YaHei', 12, 'bold'),
                                  bg='#F8F9FA', fg='#2C3E50',
                                  relief="flat", bd=1, padx=10, pady=10)
        conn_frame.pack(fill=tk.X, pady=(0, 15))
        
        # 内容框架
        conn_content = tk.Frame(conn_frame, bg='#F8F9FA')
        conn_content.pack(fill=tk.X)
        
        # 第一行：连接状态和服务器地址
        row1 = tk.Frame(conn_content, bg='#F8F9FA')
        row1.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(row1, text="🔌 状态:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 5))
        self.status_label = tk.Label(row1, text="●断开", foreground="#E74C3C",
                                    font=('Microsoft YaHei', 10, 'bold'),
                                    bg='#F8F9FA')
        self.status_label.pack(side=tk.LEFT, padx=(0, 20))
        
        tk.Label(row1, text="🌐 服务器:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 5))
        self.server_label = tk.Label(row1, text=self.config.api_base_url, 
                                    foreground="#3498DB", font=('Microsoft YaHei', 10),
                                    bg='#F8F9FA', cursor="hand2")
        self.server_label.pack(side=tk.LEFT, padx=(0, 20))
        
        # 第二行：配置和控制
        row2 = tk.Frame(conn_content, bg='#F8F9FA')
        row2.pack(fill=tk.X)
        
        tk.Label(row2, text="🏠 主机:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 5))
        self.host_var = tk.StringVar(value=self.config.config["api_host"])
        host_entry = tk.Entry(row2, textvariable=self.host_var, width=15,
                             font=('Microsoft YaHei', 10), relief="flat", bd=1)
        host_entry.pack(side=tk.LEFT, padx=(0, 10))
        
        tk.Label(row2, text="🔌 端口:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 5))
        self.port_var = tk.StringVar(value=str(self.config.config["api_port"]))
        port_entry = tk.Entry(row2, textvariable=self.port_var, width=8,
                             font=('Microsoft YaHei', 10), relief="flat", bd=1)
        port_entry.pack(side=tk.LEFT, padx=(0, 10))
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 10, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 12,
            'pady': 6
        }
        
        connect_btn = tk.Button(row2, text="🔗 连接", 
                               bg="#27AE60", fg="white",
                               activebackground="#2ECC71",
                               command=self.connect_server, **btn_style)
        connect_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        config_btn = tk.Button(row2, text="⚙️ 配置", 
                              bg="#9B59B6", fg="white",
                              activebackground="#8E44AD",
                              command=self.show_config_dialog, **btn_style)
        config_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        refresh_btn = tk.Button(row2, text="🔄 刷新", 
                               bg="#3498DB", fg="white",
                               activebackground="#2980B9",
                               command=self.refresh_all_data, **btn_style)
        refresh_btn.pack(side=tk.LEFT)
    
    def create_notebook(self, parent):
        """创建选项卡"""
        self.notebook = ttk.Notebook(parent)
        self.notebook.pack(fill=tk.BOTH, expand=True)
        
        # 料盘管理选项卡
        self.create_plate_tab()
        
        # 样品管理选项卡
        self.create_sample_tab()
        
        # 查询功能选项卡
        self.create_query_tab()
    
    def create_plate_tab(self):
        """创建料盘管理选项卡"""
        plate_frame = tk.Frame(self.notebook, bg='#F8F9FA', padx=15, pady=15)
        self.notebook.add(plate_frame, text="📋 料盘管理")
        
        # 料盘列表
        list_frame = tk.LabelFrame(plate_frame, text="📋 料盘列表", 
                                  font=('Microsoft YaHei', 12, 'bold'),
                                  bg='#F8F9FA', fg='#2C3E50',
                                  relief="flat", bd=1, padx=10, pady=10)
        list_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 15))
        
        # 内容框架
        list_content = tk.Frame(list_frame, bg='#F8F9FA')
        list_content.pack(fill=tk.BOTH, expand=True)
        
        # 创建Treeview
        columns = ("名称", "容量", "已占用", "可用", "禁用", "描述")
        self.plate_tree = ttk.Treeview(list_content, columns=columns, show="headings", height=8)
        
        for col in columns:
            self.plate_tree.heading(col, text=col)
            self.plate_tree.column(col, width=100)
        
        # 滚动条
        plate_scrollbar = ttk.Scrollbar(list_content, orient="vertical", command=self.plate_tree.yview)
        self.plate_tree.configure(yscrollcommand=plate_scrollbar.set)
        
        self.plate_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        plate_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 操作按钮
        plate_btn_frame = tk.Frame(plate_frame, bg='#F8F9FA')
        plate_btn_frame.pack(fill=tk.X)
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 10, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 15,
            'pady': 8
        }
        
        refresh_plates_btn = tk.Button(plate_btn_frame, text="🔄 刷新列表", 
                                      bg="#3498DB", fg="white",
                                      activebackground="#2980B9",
                                      command=self.refresh_plates, **btn_style)
        refresh_plates_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        create_plate_btn = tk.Button(plate_btn_frame, text="➕ 创建料盘", 
                                    bg="#27AE60", fg="white",
                                    activebackground="#2ECC71",
                                    command=self.create_plate, **btn_style)
        create_plate_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        edit_plate_btn = tk.Button(plate_btn_frame, text="✏️ 修改料盘", 
                                  bg="#F39C12", fg="white",
                                  activebackground="#E67E22",
                                  command=self.edit_plate, **btn_style)
        edit_plate_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        delete_plate_btn = tk.Button(plate_btn_frame, text="🗑️ 删除料盘", 
                                    bg="#E74C3C", fg="white",
                                    activebackground="#C0392B",
                                    command=self.delete_plate, **btn_style)
        delete_plate_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        view_positions_btn = tk.Button(plate_btn_frame, text="👁️ 查看料位", 
                                      bg="#9B59B6", fg="white",
                                      activebackground="#8E44AD",
                                      command=self.view_positions, **btn_style)
        view_positions_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        clear_positions_btn = tk.Button(plate_btn_frame, text="🧹 批量清空", 
                                       bg="#FF6B6B", fg="white",
                                       activebackground="#FF5252",
                                       command=self.clear_plate_positions, **btn_style)
        clear_positions_btn.pack(side=tk.LEFT)
    
    def create_sample_tab(self):
        """创建样品管理选项卡"""
        sample_frame = tk.Frame(self.notebook, bg='#F8F9FA', padx=15, pady=15)
        self.notebook.add(sample_frame, text="📋 样品管理")
        
        # 创建左右分栏布局
        main_paned = tk.PanedWindow(sample_frame, orient=tk.HORIZONTAL, bg='#F8F9FA',
                                   sashwidth=8, sashrelief="flat")
        main_paned.pack(fill=tk.BOTH, expand=True)
        
        # 左侧操作区
        left_frame = tk.Frame(main_paned, bg='#F8F9FA', width=400)
        main_paned.add(left_frame, minsize=350)
        
        # 右侧料位展示区
        right_frame = tk.Frame(main_paned, bg='#F8F9FA')
        main_paned.add(right_frame, minsize=500)
        
        # 创建左侧操作区内容
        self.create_sample_operations(left_frame)
        
        # 创建右侧料位展示区内容
        self.create_sample_position_view(right_frame)
    
    def create_sample_operations(self, parent):
        """创建样品操作区"""
        # 样品放置区
        place_frame = tk.LabelFrame(parent, text="📥 样品放置", 
                                   font=('Microsoft YaHei', 12, 'bold'),
                                   bg='#F8F9FA', fg='#2C3E50',
                                   relief="flat", bd=1)
        place_frame.pack(fill=tk.X, pady=(0, 15), padx=5)
        
        # 内容框架
        place_content = tk.Frame(place_frame, bg='#F8F9FA')
        place_content.pack(fill=tk.X, padx=10, pady=10)
        
        # 样品ID输入
        row1 = tk.Frame(place_content, bg='#F8F9FA')
        row1.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(row1, text="🏷️ 样品ID:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.sample_id_var = tk.StringVar()
        sample_entry = tk.Entry(row1, textvariable=self.sample_id_var, width=30,
                               font=('Microsoft YaHei', 10), relief="flat", bd=1)
        sample_entry.pack(fill=tk.X, pady=(5, 0))
        
        # 料盘选择
        row2 = tk.Frame(place_content, bg='#F8F9FA')
        row2.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(row2, text="📋 料盘:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.plate_combo_var = tk.StringVar()
        self.plate_combo = ttk.Combobox(row2, textvariable=self.plate_combo_var, width=28,
                                       font=('Microsoft YaHei', 10))
        self.plate_combo.pack(fill=tk.X, pady=(5, 0))
        # 绑定料盘选择事件
        self.plate_combo.bind('<<ComboboxSelected>>', self.on_plate_selected)
        
        # 料位输入
        row3 = tk.Frame(place_content, bg='#F8F9FA')
        row3.pack(fill=tk.X, pady=(0, 15))
        
        tk.Label(row3, text="📍 料位:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.position_var = tk.StringVar()
        position_entry = tk.Entry(row3, textvariable=self.position_var, width=30,
                                 font=('Microsoft YaHei', 10), relief="flat", bd=1)
        position_entry.pack(fill=tk.X, pady=(5, 0))
        
        # 操作按钮
        btn_frame = tk.Frame(place_content, bg='#F8F9FA')
        btn_frame.pack(fill=tk.X)
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 10, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 12,
            'pady': 6
        }
        
        place_btn = tk.Button(btn_frame, text="📥 放置样品", 
                             bg="#27AE60", fg="white",
                             activebackground="#2ECC71",
                             command=self.place_sample, **btn_style)
        place_btn.pack(side=tk.LEFT, padx=(0, 8))
        
        get_pos_btn = tk.Button(btn_frame, text="🔍 获取可用", 
                               bg="#3498DB", fg="white",
                               activebackground="#2980B9",
                               command=self.get_available_position, **btn_style)
        get_pos_btn.pack(side=tk.LEFT)
        
        # 样品移除区
        remove_frame = tk.LabelFrame(parent, text="🗑️ 样品移除", 
                                    font=('Microsoft YaHei', 12, 'bold'),
                                    bg='#F8F9FA', fg='#2C3E50',
                                    relief="flat", bd=1)
        remove_frame.pack(fill=tk.X, pady=(0, 15), padx=5)
        
        # 内容框架
        remove_content = tk.Frame(remove_frame, bg='#F8F9FA')
        remove_content.pack(fill=tk.X, padx=10, pady=10)
        
        # 料盘选择
        plate_row = tk.Frame(remove_content, bg='#F8F9FA')
        plate_row.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(plate_row, text="📋 料盘:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.remove_plate_var = tk.StringVar()
        self.remove_plate_combo = ttk.Combobox(plate_row, textvariable=self.remove_plate_var, width=28,
                                              font=('Microsoft YaHei', 10))
        self.remove_plate_combo.pack(fill=tk.X, pady=(5, 0))
        
        # 样品ID输入
        sample_row = tk.Frame(remove_content, bg='#F8F9FA')
        sample_row.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(sample_row, text="🏷️ 样品ID:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.remove_sample_var = tk.StringVar()
        remove_entry = tk.Entry(sample_row, textvariable=self.remove_sample_var, width=30,
                               font=('Microsoft YaHei', 10), relief="flat", bd=1)
        remove_entry.pack(fill=tk.X, pady=(5, 0))
        
        remove_btn = tk.Button(remove_content, text="🗑️ 移除样品", 
                              bg="#E74C3C", fg="white",
                              activebackground="#C0392B",
                              command=self.remove_sample, **btn_style)
        remove_btn.pack(pady=(10, 0))
    
    def create_sample_position_view(self, parent):
        """创建料位展示区"""
        # 标题区
        header_frame = tk.Frame(parent, bg='#F8F9FA')
        header_frame.pack(fill=tk.X, pady=(0, 15))
        
        title_label = tk.Label(header_frame, text="🔲 料位布局", 
                              font=('Microsoft YaHei', 16, 'bold'),
                              bg='#F8F9FA', fg='#2C3E50')
        title_label.pack(side=tk.LEFT)
        
        # 统计信息区
        self.stats_frame = tk.Frame(header_frame, bg='#F8F9FA')
        self.stats_frame.pack(side=tk.RIGHT)
        
        # 料位展示区
        position_frame = tk.LabelFrame(parent, text="", 
                                      font=('Microsoft YaHei', 10),
                                      bg='#F8F9FA', fg='#2C3E50',
                                      relief="flat", bd=1)
        position_frame.pack(fill=tk.BOTH, expand=True, padx=5)
        
        # 创建滚动区域
        self.position_canvas = tk.Canvas(position_frame, bg='#FFFFFF', highlightthickness=0)
        position_scrollbar = tk.Scrollbar(position_frame, orient="vertical", command=self.position_canvas.yview)
        self.position_container = tk.Frame(self.position_canvas, bg='#FFFFFF')
        
        self.position_container.bind('<Configure>', self.on_position_frame_configure)
        self.position_canvas.configure(yscrollcommand=position_scrollbar.set)
        self.position_canvas.bind('<Configure>', self.on_position_canvas_configure)
        
        self.position_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        position_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.position_canvas.create_window((0, 0), window=self.position_container, anchor="nw")
        
        # 初始化变量
        self.current_plate_positions = []
        self.position_buttons = {}
        self.stats_cards = {}
        
        # 显示占位符
        self.show_position_placeholder()
    
    def on_plate_selected(self, event=None):
        """料盘选择事件"""
        plate_name = self.plate_combo_var.get().strip()
        if plate_name:
            self.load_plate_positions(plate_name)
    
    def load_plate_positions(self, plate_name):
        """加载料盘料位信息"""
        try:
            result = self.api_request("GET", f"/api/plates/{plate_name}/positions")
            self.current_plate_positions = result['positions']
            self.update_position_display()
        except Exception as e:
            messagebox.showerror("错误", f"加载料位信息失败: {str(e)}")
            self.current_plate_positions = []
            self.show_position_placeholder()
    
    def update_position_display(self):
        """更新料位显示"""
        # 清空现有内容
        for widget in self.position_container.winfo_children():
            widget.destroy()
        
        self.position_buttons.clear()
        
        if not self.current_plate_positions:
            self.show_position_placeholder()
            return
        
        # 更新统计信息
        self.update_stats_display()
        
        # 计算网格布局
        import math
        total_positions = len(self.current_plate_positions)
        cols = min(8, math.ceil(math.sqrt(total_positions)))  # 最多8列
        rows = math.ceil(total_positions / cols)
        
        # 创建料位按钮
        for i, pos in enumerate(self.current_plate_positions):
            row = i // cols
            col = i % cols
            
            btn = self.create_position_button_sample(self.position_container, pos)
            btn.grid(row=row, column=col, padx=3, pady=3, sticky="nsew")
            
            self.position_buttons[pos["position_index"]] = btn
        
        # 配置网格权重
        for i in range(rows):
            self.position_container.grid_rowconfigure(i, weight=1)
        for i in range(cols):
            self.position_container.grid_columnconfigure(i, weight=1)
        
        # 更新滚动区域
        self.position_container.update_idletasks()
        self.position_canvas.configure(scrollregion=self.position_canvas.bbox("all"))
    
    def create_position_button_sample(self, parent, position):
        """创建料位按钮（样品管理用）"""
        pos_index = position["position_index"]
        sample_id = position["sample_id"]
        status = position["status"]
        
        # 根据状态确定颜色
        if status == "disabled":
            bg_color = "#BDC3C7"  # 灰色 - 禁用
            text_color = "#7F8C8D"
        elif sample_id and sample_id != "":
            bg_color = "#E74C3C"  # 红色 - 占用
            text_color = "white"
        else:
            bg_color = "#27AE60"  # 绿色 - 可用
            text_color = "white"
        
        # 智能处理样品ID显示
        if sample_id and len(sample_id) > 16:
            # 如果超过16个字符，显示前14个+省略号
            display_id = sample_id[:14] + ".."
        else:
            display_id = sample_id if sample_id else "空"
        
        # 创建按钮 - 增加高度以适应更多文本
        btn = tk.Button(parent, 
                       text=f"{pos_index}\n{display_id}",
                       bg=bg_color, fg=text_color,
                       font=('Microsoft YaHei', 8, 'bold'),
                       relief="flat", bd=1,
                       width=10, height=4,  # 增加宽度从8到10，高度从3到4
                       cursor="hand2",
                       command=lambda: self.on_sample_position_click(pos_index))
        
        # 为超长ID添加工具提示
        if sample_id and len(sample_id) > 16:
            self.create_tooltip_for_button(btn, f"完整ID: {sample_id}")
        
        return btn
    
    def create_tooltip_for_button(self, widget, text):
        """为按钮创建工具提示"""
        tooltip_window = None
        
        def show_tooltip(event):
            nonlocal tooltip_window
            if tooltip_window:
                return
            
            tooltip_window = tk.Toplevel()
            tooltip_window.wm_overrideredirect(True)
            tooltip_window.wm_geometry(f"+{event.x_root+10}+{event.y_root+10}")
            tooltip_window.configure(bg='#2C3E50')
            
            label = tk.Label(tooltip_window, text=text, 
                           background="#2C3E50", foreground="white",
                           relief="solid", borderwidth=1, 
                           font=('Microsoft YaHei', 9),
                           padx=8, pady=6)
            label.pack()
        
        def hide_tooltip(event=None):
            nonlocal tooltip_window
            if tooltip_window:
                tooltip_window.destroy()
                tooltip_window = None
        
        # 绑定事件
        widget.bind("<Enter>", show_tooltip)
        widget.bind("<Leave>", hide_tooltip)
        widget.bind("<Button-1>", hide_tooltip)
    
    def on_sample_position_click(self, position_index):
        """料位点击事件"""
        # 自动填入料位号
        self.position_var.set(str(position_index))
        
        # 查找当前料位的信息
        current_position = next((p for p in self.current_plate_positions 
                               if p["position_index"] == position_index), None)
        
        if current_position:
            sample_id = current_position.get("sample_id", "")
            status = current_position.get("status", "")
            
            # 如果料位有样品占用，自动填入移除功能的样品ID
            if sample_id and sample_id != "" and sample_id != "#999" and status == "occupied":
                self.remove_sample_var.set(sample_id)
                # 同时确保移除功能的料盘选择正确
                current_plate = self.plate_combo_var.get().strip()
                if current_plate:
                    self.remove_plate_var.set(current_plate)
            else:
                # 如果料位没有样品，清空移除功能的样品ID
                self.remove_sample_var.set("")
        
        # 高亮显示选中的料位
        self.highlight_sample_position(position_index)
    
    def highlight_sample_position(self, pos_index):
        """高亮显示料位"""
        # 重置所有按钮样式
        for idx, btn in self.position_buttons.items():
            pos = next((p for p in self.current_plate_positions if p["position_index"] == idx), None)
            if pos:
                status = pos["status"]
                sample_id = pos["sample_id"]
                
                if status == "disabled":
                    btn.config(bg="#BDC3C7", relief="flat", bd=1)
                elif sample_id and sample_id != "":
                    btn.config(bg="#E74C3C", relief="flat", bd=1)
                else:
                    btn.config(bg="#27AE60", relief="flat", bd=1)
        
        # 高亮选中的料位
        if pos_index in self.position_buttons:
            self.position_buttons[pos_index].config(relief="solid", bd=3)
    
    def update_stats_display(self):
        """更新统计信息显示"""
        if not self.current_plate_positions:
            return
        
        # 统计各种状态的料位数量
        total = len(self.current_plate_positions)
        occupied = sum(1 for p in self.current_plate_positions 
                      if p["sample_id"] and p["sample_id"] != "" and p["sample_id"] != "#999")
        disabled = sum(1 for p in self.current_plate_positions if p["sample_id"] == "#999")
        available = total - occupied - disabled
        
        # 清空现有统计卡片
        for widget in self.stats_frame.winfo_children():
            widget.destroy()
        self.stats_cards.clear()
        
        # 创建统计卡片
        self.create_stats_card(self.stats_frame, "总计", total, "#3498DB", 0)
        self.create_stats_card(self.stats_frame, "可用", available, "#27AE60", 1)
        self.create_stats_card(self.stats_frame, "占用", occupied, "#E74C3C", 2)
        self.create_stats_card(self.stats_frame, "禁用", disabled, "#95A5A6", 3)
    
    def create_stats_card(self, parent, label, value, color, column):
        """创建统计卡片"""
        card = tk.Frame(parent, bg=color, relief="flat", bd=0)
        card.grid(row=0, column=column, padx=5, sticky="ew")
        
        value_label = tk.Label(card, text=str(value), 
                              font=('Microsoft YaHei', 14, 'bold'),
                              bg=color, fg="white")
        value_label.pack(pady=(8, 2))
        
        label_label = tk.Label(card, text=label, 
                              font=('Microsoft YaHei', 9),
                              bg=color, fg="white")
        label_label.pack(pady=(0, 8))
        
        # 保存引用以便更新
        self.stats_cards[label] = (value_label, label_label)
        
        return card
    
    def show_position_placeholder(self):
        """显示料位占位符"""
        # 清空现有内容
        for widget in self.position_container.winfo_children():
            widget.destroy()
        
        # 清空统计信息
        for widget in self.stats_frame.winfo_children():
            widget.destroy()
        
        placeholder = tk.Label(self.position_container, 
                              text="请选择料盘查看料位布局",
                              font=('Microsoft YaHei', 14),
                              bg='#FFFFFF', fg='#95A5A6')
        placeholder.pack(expand=True, pady=50)
    
    def clear_sample_inputs(self):
        """清空样品输入框"""
        self.sample_id_var.set("")
        self.position_var.set("")
        self.remove_sample_var.set("")
        self.search_sample_var.set("")
        
        # 清空查询结果
        if hasattr(self, 'query_tree') and self.query_tree:
            self.query_tree.delete(*self.query_tree.get_children())
        
        # 重置高亮
        self.highlighted_position = None
        if hasattr(self, 'current_plate_positions'):
            self.update_position_display()
    
    def on_position_frame_configure(self, event):
        """料位框架配置事件"""
        self.position_canvas.configure(scrollregion=self.position_canvas.bbox("all"))
    
    def on_position_canvas_configure(self, event):
        """料位画布配置事件"""
        canvas_width = event.width
        self.position_canvas.itemconfig(self.position_canvas.find_all()[0], width=canvas_width)
    
    def create_query_tab(self):
        """创建查询功能选项卡"""
        query_frame = tk.Frame(self.notebook, bg='#F8F9FA', padx=15, pady=15)
        self.notebook.add(query_frame, text="🔍 查询功能")
        
        # 搜索区域
        search_frame = tk.LabelFrame(query_frame, text="🔍 样品查询", 
                                    font=('Microsoft YaHei', 12, 'bold'),
                                    bg='#F8F9FA', fg='#2C3E50',
                                    relief="flat", bd=1, padx=10, pady=10)
        search_frame.pack(fill=tk.X, pady=(0, 15))
        
        # 搜索内容
        search_content = tk.Frame(search_frame, bg='#F8F9FA')
        search_content.pack(fill=tk.X)
        
        tk.Label(search_content, text="🏷️ 样品ID:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W, pady=(0, 5))
        
        search_row = tk.Frame(search_content, bg='#F8F9FA')
        search_row.pack(fill=tk.X)
        
        self.search_sample_var = tk.StringVar()
        search_entry = tk.Entry(search_row, textvariable=self.search_sample_var, width=30,
                               font=('Microsoft YaHei', 10), relief="flat", bd=1)
        search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 10, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 15,
            'pady': 8
        }
        
        search_btn = tk.Button(search_row, text="🔍 查询", 
                              bg="#3498DB", fg="white",
                              activebackground="#2980B9",
                              command=self.search_sample, **btn_style)
        search_btn.pack(side=tk.RIGHT)
        
        # 结果区域
        result_frame = tk.LabelFrame(query_frame, text="📊 查询结果", 
                                    font=('Microsoft YaHei', 12, 'bold'),
                                    bg='#F8F9FA', fg='#2C3E50',
                                    relief="flat", bd=1, padx=10, pady=10)
        result_frame.pack(fill=tk.BOTH, expand=True)
        
        # 结果内容
        result_content = tk.Frame(result_frame, bg='#F8F9FA')
        result_content.pack(fill=tk.BOTH, expand=True)
        
        # 创建Treeview用于显示查询结果
        columns = ("样品ID", "料盘", "料位", "状态")
        self.query_tree = ttk.Treeview(result_content, columns=columns, show="headings", height=10)
        
        for col in columns:
            self.query_tree.heading(col, text=col)
            self.query_tree.column(col, width=150)
        
        # 滚动条
        query_scrollbar = ttk.Scrollbar(result_content, orient="vertical", command=self.query_tree.yview)
        self.query_tree.configure(yscrollcommand=query_scrollbar.set)
        
        self.query_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        query_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    
    # ==================== 连接管理方法 ====================
    
    def connect_server(self):
        """连接服务器"""
        # 更新配置
        self.config.config["api_host"] = self.host_var.get().strip()
        try:
            self.config.config["api_port"] = int(self.port_var.get().strip())
        except ValueError:
            messagebox.showerror("错误", "请输入有效的端口号")
            return
        
        # 保存配置
        self.config.save_config()
        
        # 检查连接
        if self.check_connection():
            messagebox.showinfo("成功", "已连接到服务器")
            self.refresh_all_data()
        else:
            messagebox.showerror("连接失败", "无法连接到服务器，请检查地址和端口")
    
    def check_connection(self):
        """检查服务器连接状态"""
        try:
            response = requests.get(f"{self.config.api_base_url}/api/health", 
                                  timeout=self.config.config.get("timeout", 10))
            if response.status_code == 200:
                result = response.json()
                if result.get("status") == "healthy":
                    self.server_connected = True
                    self.status_label.config(text="●已连接", foreground="#27AE60")
                    self.server_label.config(text=self.config.api_base_url)
                    return True
            
            self.server_connected = False
            self.status_label.config(text="●断开", foreground="#E74C3C")
            return False
            
        except Exception as e:
            self.server_connected = False
            self.status_label.config(text="●断开", foreground="#E74C3C")
            return False
    
    def start_connection_check(self):
        """启动定期连接检查"""
        def check_loop():
            while True:
                try:
                    self.check_connection()
                    time.sleep(5)  # 每5秒检查一次
                except Exception:
                    pass
        
        # 在后台线程中运行连接检查
        import threading
        thread = threading.Thread(target=check_loop, daemon=True)
        thread.start()
    
    def show_config_dialog(self):
        """显示配置对话框"""
        ConfigDialog(self.root, self.config)
    
    # ==================== API调用方法 ====================
    
    def api_request(self, method: str, endpoint: str, data=None) -> Dict[str, Any]:
        """发送API请求"""
        if not self.server_connected:
            raise Exception("服务器未连接")
        
        url = f"{self.config.api_base_url}{endpoint}"
        
        try:
            if method.upper() == "GET":
                response = requests.get(url, timeout=self.config.config["connection_timeout"])
            elif method.upper() == "POST":
                response = requests.post(url, json=data, timeout=self.config.config["connection_timeout"])
            elif method.upper() == "PUT":
                response = requests.put(url, json=data, timeout=self.config.config["connection_timeout"])
            elif method.upper() == "DELETE":
                response = requests.delete(url, timeout=self.config.config["connection_timeout"])
            else:
                raise ValueError(f"不支持的HTTP方法: {method}")
            
            if response.status_code == 200:
                return response.json()
            else:
                error_detail = response.json().get("detail", "未知错误") if response.content else "请求失败"
                raise Exception(f"API错误 ({response.status_code}): {error_detail}")
                
        except requests.exceptions.RequestException as e:
            raise Exception(f"网络请求失败: {str(e)}")
    
    # ==================== 数据刷新方法 ====================
    
    def refresh_all_data(self):
        """刷新所有数据"""
        if self.server_connected:
            self.refresh_plates()
            self.log_message("所有数据已刷新")
    
    def refresh_plates(self):
        """刷新料盘列表"""
        try:
            plates = self.api_request("GET", "/api/plates")
            
            # API直接返回料盘列表，不是包装格式
            if isinstance(plates, list):
                # 更新料盘树
                self.plate_tree.delete(*self.plate_tree.get_children())
                
                plate_names = []
                for plate in plates:
                    name = plate.get("name", "")
                    capacity = plate.get("capacity", 0)
                    occupied = plate.get("occupied_count", 0)
                    available = plate.get("available_count", 0)  # 使用API返回的available_count
                    disabled = plate.get("disabled_count", 0)
                    description = plate.get("description", "")
                    
                    self.plate_tree.insert("", "end", values=(
                        name, capacity, occupied, available, disabled, description
                    ))
                    plate_names.append(name)
                
                # 更新下拉框选项
                if hasattr(self, 'plate_combo') and self.plate_combo:
                    self.plate_combo['values'] = plate_names
                    
                # 更新移除样品的料盘下拉框
                if hasattr(self, 'remove_plate_combo') and self.remove_plate_combo:
                    self.remove_plate_combo['values'] = plate_names
                
                self.log_message(f"已刷新料盘列表，共 {len(plates)} 个料盘")
            else:
                error_msg = "料盘数据格式错误"
                messagebox.showerror("刷新失败", error_msg)
                self.log_message(f"刷新料盘失败: {error_msg}")
                
        except Exception as e:
            error_msg = f"刷新料盘列表时发生错误: {str(e)}"
            messagebox.showerror("错误", error_msg)
            self.log_message(error_msg)
    
    # ==================== 料盘管理方法 ====================
    
    def create_plate(self):
        """创建料盘"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        from src.ui.ui_manager import PlateDialog
        dialog = PlateDialog(self.root, "创建料盘")
        if dialog.result:
            try:
                result = self.api_request("POST", "/api/plates", dialog.result)
                messagebox.showinfo("成功", result["message"])
                self.refresh_plates()
            except Exception as e:
                messagebox.showerror("错误", f"创建料盘失败: {str(e)}")
    
    def edit_plate(self):
        """修改料盘"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要修改的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        try:
            plates = self.api_request("GET", "/api/plates")
            # plates 直接是列表
            current_plate = next((p for p in plates if p["name"] == plate_name), None)
            if not current_plate:
                messagebox.showerror("错误", "找不到料盘信息")
                return
            
            from src.ui.ui_manager import PlateDialog
            dialog = PlateDialog(self.root, "修改料盘", current_plate)
            if dialog.result:
                try:
                    # 尝试正常更新
                    result = self.api_request("PUT", f"/api/plates/{plate_name}", dialog.result)
                    messagebox.showinfo("成功", result["message"])
                    self.refresh_plates()
                except Exception as e:
                    error_msg = str(e)
                    # 检查是否是容量冲突错误
                    if "CAPACITY_CONFLICT:" in error_msg:
                        # 提取错误信息
                        conflict_msg = error_msg.split("CAPACITY_CONFLICT:")[1]
                        
                        # 弹出确认对话框
                        confirm_msg = f"{conflict_msg}\n\n是否要清空料盘中的所有样品并重新设置容量？\n\n警告：此操作将删除料盘中的所有样品数据！"
                        if messagebox.askyesno("容量冲突", confirm_msg, icon='warning'):
                            try:
                                # 使用重置API
                                result = self.api_request("PUT", f"/api/plates/{plate_name}/reset", dialog.result)
                                messagebox.showinfo("成功", result["message"])
                                self.refresh_plates()
                            except Exception as reset_e:
                                messagebox.showerror("错误", f"重置料盘失败: {str(reset_e)}")
                    else:
                        # 其他错误直接显示
                        messagebox.showerror("错误", f"修改料盘失败: {error_msg}")
        except Exception as e:
            messagebox.showerror("错误", f"修改料盘失败: {str(e)}")
    
    def delete_plate(self):
        """删除料盘"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要删除的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        if messagebox.askyesno("确认删除", f"确定要删除料盘 '{plate_name}' 吗？\n注意：这将删除料盘中的所有样品！"):
            try:
                result = self.api_request("DELETE", f"/api/plates/{plate_name}")
                messagebox.showinfo("成功", result["message"])
                self.refresh_plates()
            except Exception as e:
                messagebox.showerror("错误", f"删除料盘失败: {str(e)}")
    
    def view_positions(self):
        """查看料位详情"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要查看的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        try:
            result = self.api_request("GET", f"/api/plates/{plate_name}/positions")
            # 使用增强版料盘详细视图，与main_new.py保持一致
            from src.ui.plate_detail_dialog import PlateDetailDialog
            PlateDetailDialog(self.root, plate_name, result['positions'], self.api_request)
        except Exception as e:
            messagebox.showerror("错误", f"获取料位信息失败: {str(e)}")
    
    def clear_plate_positions(self):
        """批量清空料位"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要清空的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        # 确认清空
        confirm_msg = f"确定要清空料盘 '{plate_name}' 中的所有样品吗？\n\n注意：\n• 此操作将移除所有样品\n• 禁用的料位状态将保持不变\n• 此操作不可撤销！"
        if messagebox.askyesno("确认批量清空", confirm_msg, icon='warning'):
            try:
                result = self.api_request("PUT", f"/api/plates/{plate_name}/clear")
                messagebox.showinfo("成功", result["message"])
                self.refresh_plates()
                
                # 刷新当前料位显示
                current_plate = self.plate_combo_var.get().strip()
                if current_plate == plate_name:
                    self.load_plate_positions(plate_name)
            except Exception as e:
                error_msg = str(e)
                if "没有样品需要清空" in error_msg:
                    messagebox.showinfo("提示", f"料盘 '{plate_name}' 中没有样品需要清空")
                else:
                    messagebox.showerror("错误", f"批量清空失败: {error_msg}")
    
    # ==================== 样品管理方法 ====================
    
    def place_sample(self):
        """放置样品"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        sample_id = self.sample_id_var.get().strip()
        plate_name = self.plate_combo_var.get().strip()
        position_str = self.position_var.get().strip()
        
        if not all([sample_id, plate_name, position_str]):
            messagebox.showwarning("警告", "请填写完整信息")
            return
        
        try:
            position_index = int(position_str)
            data = {
                "sample_id": sample_id,
                "plate_name": plate_name,
                "position_index": position_index
            }
            result = self.api_request("POST", "/api/samples/place", data)
            messagebox.showinfo("成功", result["message"])
            
            # 清空输入
            self.sample_id_var.set("")
            self.position_var.set("")
            
            # 刷新料盘列表
            self.refresh_plates()
            
            # 刷新当前料位显示
            if plate_name:
                self.load_plate_positions(plate_name)
        except ValueError:
            messagebox.showerror("错误", "料位必须是数字")
        except Exception as e:
            messagebox.showerror("错误", f"放置样品失败: {str(e)}")
    
    def get_available_position(self):
        """获取可用料位"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        plate_name = self.plate_combo_var.get().strip()
        if not plate_name:
            messagebox.showwarning("警告", "请选择料盘")
            return
        
        try:
            result = self.api_request("GET", f"/api/plates/{plate_name}/first-available")
            if result["available_position"] is not None:
                self.position_var.set(str(result["available_position"]))
                messagebox.showinfo("成功", f"找到可用料位: {result['available_position']}")
            else:
                messagebox.showwarning("提示", result["message"])
        except Exception as e:
            messagebox.showerror("错误", f"获取可用料位失败: {str(e)}")
    
    def remove_sample(self):
        """移除样品"""
        try:
            plate_name = self.remove_plate_var.get().strip()
            sample_id = self.remove_sample_var.get().strip()
            
            if not sample_id:
                messagebox.showerror("错误", "请输入样品ID")
                return
                
            if not plate_name:
                messagebox.showerror("错误", "请选择料盘")
                return
            
            # 构建API端点，使用新的格式
            endpoint = f"/api/samples/{plate_name}/{sample_id}"
            result = self.api_request("DELETE", endpoint)
            
            if result.get("success"):
                messagebox.showinfo("成功", f"样品 '{sample_id}' 已从料盘 '{plate_name}' 移除")
                self.remove_sample_var.set("")  # 清空输入
                
                # 如果当前显示的就是这个料盘，刷新显示
                current_plate = self.plate_combo_var.get()
                if current_plate == plate_name:
                    self.load_plate_positions(plate_name)
                    
                self.log_message(f"成功移除样品: {sample_id} (料盘: {plate_name})")
            else:
                error_msg = result.get("message", "未知错误")
                messagebox.showerror("移除失败", error_msg)
                self.log_message(f"移除样品失败: {error_msg}")
                
        except Exception as e:
            error_msg = f"移除样品时发生错误: {str(e)}"
            messagebox.showerror("错误", error_msg)
            self.log_message(error_msg)
    
    # ==================== 查询功能方法 ====================
    
    def search_sample(self):
        """查询样品位置"""
        if not self.server_connected:
            messagebox.showwarning("警告", "请先连接服务器")
            return
        
        sample_id = self.search_sample_var.get().strip()
        if not sample_id:
            messagebox.showwarning("警告", "请输入样品ID")
            return
        
        try:
            result = self.api_request("GET", f"/api/samples/{sample_id}/location")
            
            message = f"样品查询结果:\n"
            message += f"样品ID: {result['sample_id']}\n"
            message += f"料盘: {result['plate_name']}\n"
            message += f"料位: {result['position_index']}\n"
            message += f"更新时间: {result['updated_at']}\n"
            message += "-" * 50 + "\n"
            
            self.query_tree.insert("", "end", values=(
                result['sample_id'],
                result['plate_name'],
                result['position_index'],
                result['status']
            ))
            self.query_tree.see(tk.END)
            
        except Exception as e:
            error_message = f"查询失败: {str(e)}\n" + "-" * 50 + "\n"
            self.query_tree.insert("", "end", values=(
                sample_id,
                "",
                "",
                error_message
            ))
            self.query_tree.see(tk.END)
    
    def log_message(self, message: str):
        """记录日志消息"""
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
        log_message = f"[{timestamp}] {message}\n"
        
        # 检查query_tree是否存在（查询选项卡可能还未创建）
        if hasattr(self, 'query_tree') and self.query_tree:
            try:
                self.query_tree.insert("", "end", values=(
                    "",
                    "",
                    "",
                    log_message.strip()
                ))
                self.query_tree.see(tk.END)
            except tk.TclError:
                # 如果文本框已被销毁，忽略错误
                pass
        else:
            # 如果没有query_tree，可以选择打印到控制台
            print(log_message.strip())
    
    def run(self):
        """运行UI"""
        self.root.mainloop()

class ConfigDialog:
    """配置对话框"""
    
    def __init__(self, parent, config: ClientConfig):
        self.config = config
        self.result = None
        
        # 创建模态对话框
        self.dialog = tk.Toplevel(parent)
        self.dialog.title("⚙️ 连接配置")
        self.dialog.geometry("450x300")
        self.dialog.configure(bg='#F8F9FA')
        self.dialog.resizable(False, False)
        
        # 设置为模态
        self.dialog.transient(parent)
        self.dialog.grab_set()
        
        # 居中显示
        self.dialog.geometry("+%d+%d" % (parent.winfo_rootx() + 50, parent.winfo_rooty() + 50))
        
        self.create_widgets()
    
    def create_widgets(self):
        """创建配置界面组件"""
        # 主框架
        main_frame = tk.Frame(self.dialog, bg='#F8F9FA', padx=20, pady=20)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题
        title_frame = tk.Frame(main_frame, bg='#F8F9FA')
        title_frame.pack(fill=tk.X, pady=(0, 20))
        
        title_label = tk.Label(title_frame, text="⚙️ API服务器配置", 
                              font=('Microsoft YaHei', 14, 'bold'),
                              bg='#F8F9FA', fg='#2C3E50')
        title_label.pack()
        
        # 配置区域
        config_frame = tk.LabelFrame(main_frame, text="🔗 连接设置", 
                                    font=('Microsoft YaHei', 12, 'bold'),
                                    bg='#F8F9FA', fg='#2C3E50',
                                    relief="flat", bd=1, padx=15, pady=15)
        config_frame.pack(fill=tk.X, pady=(0, 20))
        
        # API主机
        host_row = tk.Frame(config_frame, bg='#F8F9FA')
        host_row.pack(fill=tk.X, pady=(0, 15))
        
        tk.Label(host_row, text="🏠 API主机:", font=('Microsoft YaHei', 11),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W, pady=(0, 5))
        self.host_var = tk.StringVar(value=self.config.config["api_host"])
        host_entry = tk.Entry(host_row, textvariable=self.host_var, width=35,
                             font=('Microsoft YaHei', 11), relief="flat", bd=1)
        host_entry.pack(fill=tk.X)
        
        # API端口  
        port_row = tk.Frame(config_frame, bg='#F8F9FA')
        port_row.pack(fill=tk.X, pady=(0, 15))
        
        tk.Label(port_row, text="🔌 API端口:", font=('Microsoft YaHei', 11),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W, pady=(0, 5))
        self.port_var = tk.StringVar(value=str(self.config.config["api_port"]))
        port_entry = tk.Entry(port_row, textvariable=self.port_var, width=35,
                             font=('Microsoft YaHei', 11), relief="flat", bd=1)
        port_entry.pack(fill=tk.X)
        
        # 超时设置
        timeout_row = tk.Frame(config_frame, bg='#F8F9FA')
        timeout_row.pack(fill=tk.X)
        
        tk.Label(timeout_row, text="⏱️ 超时时间(秒):", font=('Microsoft YaHei', 11),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W, pady=(0, 5))
        self.timeout_var = tk.StringVar(value=str(self.config.config.get("timeout", 10)))
        timeout_entry = tk.Entry(timeout_row, textvariable=self.timeout_var, width=35,
                                font=('Microsoft YaHei', 11), relief="flat", bd=1)
        timeout_entry.pack(fill=tk.X)
        
        # 按钮区域
        button_frame = tk.Frame(main_frame, bg='#F8F9FA')
        button_frame.pack(fill=tk.X)
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 11, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 20,
            'pady': 10
        }
        
        # 按钮容器
        btn_container = tk.Frame(button_frame, bg='#F8F9FA')
        btn_container.pack(expand=True)
        
        save_btn = tk.Button(btn_container, text="💾 保存配置", 
                            bg="#27AE60", fg="white",
                            activebackground="#2ECC71",
                            command=self.save_config, **btn_style)
        save_btn.pack(side=tk.LEFT, padx=(0, 15))
        
        cancel_btn = tk.Button(btn_container, text="❌ 取消", 
                              bg="#95A5A6", fg="white",
                              activebackground="#7F8C8D",
                              command=self.cancel_config, **btn_style)
        cancel_btn.pack(side=tk.LEFT)
    
    def save_config(self):
        """保存配置"""
        try:
            # 验证输入
            host = self.host_var.get().strip()
            port_str = self.port_var.get().strip()
            timeout_str = self.timeout_var.get().strip()
            
            if not host:
                messagebox.showerror("错误", "请输入API主机地址")
                return
                
            try:
                port = int(port_str)
                if port <= 0 or port > 65535:
                    raise ValueError("端口范围错误")
            except ValueError:
                messagebox.showerror("错误", "请输入有效的端口号 (1-65535)")
                return
                
            try:
                timeout = int(timeout_str)
                if timeout <= 0:
                    raise ValueError("超时时间必须大于0")
            except ValueError:
                messagebox.showerror("错误", "请输入有效的超时时间 (秒)")
                return
            
            # 更新配置
            self.config.config["api_host"] = host
            self.config.config["api_port"] = port
            self.config.config["timeout"] = timeout
            
            # 保存到文件
            self.config.save_config()
            
            self.result = "saved"
            self.dialog.destroy()
            
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败: {str(e)}")
    
    def cancel_config(self):
        """取消配置"""
        self.result = "cancelled"
        self.dialog.destroy()

def main():
    """主函数"""
    print("========================================")
    print("WMS Sample 客户端")
    print("========================================")
    print()
    
    try:
        app = WMSClientUI()
        app.run()
    except KeyboardInterrupt:
        print("\n程序被用户中断")
    except Exception as e:
        print(f"❌ 启动失败: {e}")
        import traceback
        traceback.print_exc()
        input("按回车键退出...")

if __name__ == "__main__":
    main() 